
#include "hik_api_demo.h"
#include "fh_aes.h"
#define _MAP_MODE_INIT(c,name)     {.no = c, .string = (char *)name,}
#define _MAP_DATA_INIT(c,data)     {.no = c, .len = data,}

#define _FIND_MAP_STRING(p_map,no)     p_map[no].string
#define _FIND_MAP_DATTA(p_map,no)     p_map[no].len

#define EFUSE_ENTRY_RANGE   3
#define EFUSE_USR_MAX_ENTRY_SIZE    (60)
#define EFUSE_LOCK_MASK     (0x07)

#define EFUSE_ENTRY_LENGTH  16

#define EFUSE_MATCH_KEY 0x92fc0025


#define BOOT_OWN_ENTRY_48 (48)
#define BOOT_OWN_ENTRY_49 (49)
#define BOOT_OWN_ENTRY_50 (50)
#define BOOT_OWN_ENTRY_51 (51)
#define OPTID_3_MAX_ENTRY_SIZE     (8)
/* #define CRYPTO_DEBUG */
#ifdef CRYPTO_DEBUG
#define PRINT_DBG(fmt,args...)  printf(fmt,##args)
#else
#define PRINT_DBG(fmt,args...)  do{} while(0)
#endif




struct CRYPTO_DRIVER_HANDLE g_driver_handle;

struct CRYPTO_DRIVER_HANDLE
{
    struct rt_crypto_obj *crypto_obj;
};

struct CRYPTO_WORK_MODE_MAP
{
    int no;
    char *string;
};

struct CRYPTO_ALG_MAP
{
    int no;
    char *string;
};

struct CRYPTO_KEY_LEN_MAP
{
    int no;
    int len;
};

struct CRYPTO_IV_KEY_LENGTH_MAP
{
    int no;
    int len;
};

static struct CRYPTO_WORK_MODE_MAP work_mode_map[] =
{
    _MAP_MODE_INIT(CRYPTO_WORK_MODE_ECB, "ecb"),
    _MAP_MODE_INIT(CRYPTO_WORK_MODE_CBC, "cbc"),
    _MAP_MODE_INIT(CRYPTO_WORK_MODE_CFB, "cfb"),
    _MAP_MODE_INIT(CRYPTO_WORK_MODE_OFB, "ofb"),
    _MAP_MODE_INIT(CRYPTO_WORK_MODE_CTR, "ctr"),
};

static struct CRYPTO_ALG_MAP alg_map[] =
{
    _MAP_MODE_INIT(CRYPTO_ALG_DES, "des"),
    _MAP_MODE_INIT(CRYPTO_ALG_3DES, "des3"),
    _MAP_MODE_INIT(CRYPTO_ALG_DES, "aes"),
};

static struct CRYPTO_KEY_LEN_MAP key_len_map[] =
{
    _MAP_DATA_INIT(CRYPTO_KEY_AES_128BIT, 16),
    _MAP_DATA_INIT(CRYPTO_KEY_AES_192BIT, 24),
    _MAP_DATA_INIT(CRYPTO_KEY_AES_256BIT, 32),
    _MAP_DATA_INIT(CRYPTO_KEY_DES_3KEY, 24),
    _MAP_DATA_INIT(CRYPTO_KEY_DES, 8),
};

static struct CRYPTO_IV_KEY_LENGTH_MAP iv_key_len_map[] =
{
    _MAP_DATA_INIT(CRYPTO_IV_KEY_AES_0BIT, 0),
    _MAP_DATA_INIT(CRYPTO_IV_KEY_AES_64BIT, 8),
    _MAP_DATA_INIT(CRYPTO_IV_KEY_AES_128BIT, 16),
};

int crypto_efuse_write(unsigned int u32OptId, const unsigned char *pu8Key,
        unsigned int u32KeyLen)
{
    int ret = 0;
    unsigned int status;
    unsigned int entry_id_start;
    unsigned int entry_id_end;
    unsigned int lock_check_start;
    unsigned int lock_check_end;
    unsigned int i;
    EFUSE_INFO efuse_info;
    entry_id_start = u32OptId * EFUSE_ENTRY_LENGTH;
    entry_id_end = u32OptId * EFUSE_ENTRY_LENGTH + u32KeyLen;
    lock_check_start = u32OptId;
    lock_check_end = entry_id_end / EFUSE_ENTRY_LENGTH;
    if(entry_id_end % EFUSE_ENTRY_LENGTH)
        lock_check_end++;
    if(!pu8Key){
        printf("[crypt_api]: null pu8Key get in..\n");
        return -1;
    }
    if(u32OptId > EFUSE_ENTRY_RANGE){
        printf("[crypt_api]: opt id %d is out of range, should be 0~3\n", u32OptId);
        return -1;
    }
    if(u32KeyLen % 4){
        printf("[crypt_api]: key len 0x%x, should be 4B allign\n", u32KeyLen);
        return -1;
    }
    /* optid 3 need check single*/
    if(u32OptId != EFUSE_ENTRY_RANGE){
        /* check api process all entry limit */
        if(entry_id_end > EFUSE_USR_MAX_ENTRY_SIZE){
            printf("[crypt_api]: process end entry %d out of range %d\n", entry_id_end , EFUSE_USR_MAX_ENTRY_SIZE);
            return -1;
        }
        /* check api process 48 ~ 51 entry */
        for(i = BOOT_OWN_ENTRY_48 ; i <  BOOT_OWN_ENTRY_51 + 1; i++){
            if((i > entry_id_start) && (i < entry_id_end)){
                printf("[crypt_api]: do not write entry : %d\n",i);
                return -1;
            }
        }
    }
    else {
        if(u32KeyLen > OPTID_3_MAX_ENTRY_SIZE){
            printf("[crypt_api]: optid 3 process size %d out of range %d\n",u32KeyLen,OPTID_3_MAX_ENTRY_SIZE);
            return -1;
        }
    }

    /* hw check if entry has been written already */
    ret = fh_efuse_ioctl(&efuse_info, IOCTL_EFUSE_CHECK_PRO, 0);
    if ( ret < 0 )
    {
        printf("[crypt_api]: IOCTL_EFUSE_CHECK_PRO failed. ret=%d\n", ret);
        ret = -2;
        goto out;
    }
    //status = efuse_info.status.protect_bits[(u32OptId * EFUSE_ENTRY_LENGTH) / 32];
    PRINT_DBG("protect[%d]: 0x%x\n", (u32OptId * EFUSE_ENTRY_LENGTH) / 32, status);
    for(i = entry_id_start; i < entry_id_end; i++){
        status = efuse_info.status.protect_bits[(i / 32)];
        if (!(status & (0x01 << (i % 32)))){
            printf("[crypt_api]: write entry[%d] is not permitted. status=0x%x\n",
                    i, status);
            ret = -3;
            goto out;
        }
    }

    /* if u32OptId == 3 .fix to the correct efuse entry pos.*/
    if(u32OptId != EFUSE_ENTRY_RANGE)
        efuse_info.efuse_entry_no = u32OptId * EFUSE_ENTRY_LENGTH;
    else
        efuse_info.efuse_entry_no = EFUSE_ENTRY_RANGE * EFUSE_ENTRY_LENGTH + 4;
    efuse_info.key_buff =(unsigned char*)pu8Key;
    efuse_info.key_size = u32KeyLen;

    ret = fh_efuse_ioctl(&efuse_info, IOCTL_EFUSE_WRITE_KEY, 0);
    if( ret < 0 )
    {
        printf("[crypt_api]: IOCTL_EFUSE_WRITE_KEY failed. ret=%d\n", ret);
        ret = -2;
    }

out:
    return ret;
}



int crypto_efuse_read(unsigned int u32OptId, const unsigned char *pu8Key,
        unsigned int u32KeyLen)
{

    int ret = 0;
    unsigned int status;
    EFUSE_INFO efuse_info;
	unsigned int entry_id_start;
    unsigned int entry_id_end;
    unsigned int lock_check_start;
    unsigned int lock_check_end;
    unsigned int i;
    entry_id_start = u32OptId * EFUSE_ENTRY_LENGTH;
    entry_id_end = u32OptId * EFUSE_ENTRY_LENGTH + u32KeyLen;
    lock_check_start = u32OptId;
    lock_check_end = entry_id_end / EFUSE_ENTRY_LENGTH;
    if(entry_id_end % EFUSE_ENTRY_LENGTH)
        lock_check_end++;

    if(!pu8Key){
        printf("[crypt_api]: null pu8Key get in..\n");
        return -1;
    }
    if (u32OptId > EFUSE_ENTRY_RANGE)
    {
        printf("opt id: %d is out of range, should be 0~3\n", u32OptId);
        return -1;
    }
    if(u32KeyLen % 4){
        printf("[crypt_api]: key len 0x%x, should be 4B allign\n", u32KeyLen);
        return -1;
    }
	/* optid 3 need check single*/
    if(u32OptId != EFUSE_ENTRY_RANGE){
        /* check api process all entry limit */
        if(entry_id_end > EFUSE_USR_MAX_ENTRY_SIZE){
            printf("[crypt_api]: process end entry %d out of range %d\n", entry_id_end , EFUSE_USR_MAX_ENTRY_SIZE);
            return -1;
        }
        /* check api process 48 ~ 51 entry */
        for(i = BOOT_OWN_ENTRY_48 ; i <  BOOT_OWN_ENTRY_51 + 1; i++){
            if((i > entry_id_start) && (i < entry_id_end)){
                printf("[crypt_api]: do not read entry : %d\n",i);
                return -1;
            }
        }

    }
    else {
        if(u32KeyLen > OPTID_3_MAX_ENTRY_SIZE){
            printf("[crypt_api]: optid 3 process size %d out of range %d\n",u32KeyLen,OPTID_3_MAX_ENTRY_SIZE);
            return -1;
        }
    }

    efuse_info.status.efuse_apb_lock = 0;
    efuse_info.status.aes_ahb_lock = 0;
    ret = fh_efuse_ioctl(&efuse_info, IOCTL_EFUSE_CHECK_LOCK, 0);
    if (ret < 0)
    {
        printf("[crypt_api]: IOCTL_EFUSE_CHECK_LOCK failed. ret=%d\n", ret);
        ret = -2;
        goto out;
    }
    /* 1 means lock.. */
    status = efuse_info.status.efuse_apb_lock;
    for(i = lock_check_start; i < lock_check_end; i++){
        if (status & (0x01 << i)){
            printf("[crypt_api]: u32OptId : %d. locked already.. lock status : %x\n", i, status);
            ret = -2;
            goto out;
        }
    }
    //efuse_info.efuse_entry_no = u32OptId * EFUSE_ENTRY_LENGTH;
    if(u32OptId != EFUSE_ENTRY_RANGE)
        efuse_info.efuse_entry_no = u32OptId * EFUSE_ENTRY_LENGTH;
    else
        efuse_info.efuse_entry_no = EFUSE_ENTRY_RANGE * EFUSE_ENTRY_LENGTH + 4;
    efuse_info.key_buff =(unsigned char *)pu8Key;
    efuse_info.key_size = u32KeyLen;
    efuse_info.status.error = EFUSE_MATCH_KEY;

    ret = fh_efuse_ioctl(&efuse_info, IOCTL_EFUSE_READ_ENTRY, 0);
    if (ret < 0)
    {
        printf("[crypt_api]: IOCTL_EFUSE_READ_KEY failed. ret=%d\n", ret);
        ret = -2;
    }

out:
    return ret;
}

int FH_CRYPTO_SetLock(unsigned int u32Efuse_LockBits){

    EFUSE_INFO efuse_info;
    unsigned int status;
    int ret = 0;
    efuse_info.status.efuse_apb_lock = 0x0;
	efuse_info.status.aes_ahb_lock = 0x0;
    if(u32Efuse_LockBits == 0){
        printf("[crypt_api]: u32Efuse_LockBits should not be 0.\n");
        return -1;
    }
    if(u32Efuse_LockBits > EFUSE_LOCK_MASK){
        printf("[crypt_api]: u32Efuse_LockBits 0x%x should not larger than 0x%x\n",u32Efuse_LockBits,EFUSE_LOCK_MASK);
        return -1;
    }
    if((u32Efuse_LockBits & EFUSE_LOCK_MASK) > EFUSE_LOCK_MASK){
        printf("[crypt_api]: u32Efuse_LockBits: 0x%x is out of range, max is 0x%x\n", u32Efuse_LockBits ,EFUSE_LOCK_MASK);
        return -1;
    }

    // add hw check...read
    efuse_info.status.efuse_apb_lock = 0;
    efuse_info.status.aes_ahb_lock = 0;
    ret = fh_efuse_ioctl(&efuse_info, IOCTL_EFUSE_CHECK_LOCK, 0);
    if (ret < 0)
    {
        printf("[crypt_api]: IOCTL_EFUSE_CHECK_LOCK failed. ret=%d\n", ret);
        return -1;
    }
    /* 1 means lock.. */
    status = efuse_info.status.efuse_apb_lock;
    if(u32Efuse_LockBits & status){
        printf("[crypt_api]: IOCTL_EFUSE_CHECK_LOCK failed. lock bits : 0x%x; HW get : 0x%x\n", u32Efuse_LockBits, status);
        return -1;
    }

    efuse_info.status.efuse_apb_lock = u32Efuse_LockBits;
    // lock all the aes read .
    efuse_info.status.aes_ahb_lock = 0x0f;

	fh_efuse_ioctl(&efuse_info, IOCTL_EFUSE_SET_LOCK_DATA, 0);

    return 0;
}


int FH_CRYPTO_Init(void)
{

    return 0;
}

int FH_CRYPTO_DeInit(void)
{
    return 0;
}

int FH_CRYPTO_CreateHandle(CRYPTO_HANDLE *phCipher)
{

    struct CRYPTO_DRIVER_HANDLE *driver_handle;
    if(!phCipher){
        printf("[crypt_api]: NULL handle in..\n");
        return -1;
    }
    memset(phCipher,0,sizeof(CRYPTO_HANDLE));
    driver_handle = &g_driver_handle;//rt_malloc(sizeof(struct CRYPTO_DRIVER_HANDLE));

    phCipher->opfd = (int) driver_handle;

    return 0;
}

int FH_CRYPTO_DestroyHandle(CRYPTO_HANDLE *phCipher)
{
    struct CRYPTO_DRIVER_HANDLE *driver_handle;

    driver_handle = (struct CRYPTO_DRIVER_HANDLE *) phCipher->opfd;
    //rt_free(driver_handle);
    driver_handle = NULL;

    return 0;
}

int FH_CRYPTO_ConfigHandle(CRYPTO_HANDLE *phCipher, CRYPTO_CTRL_S *pstCtrl)
{
    struct CRYPTO_DRIVER_HANDLE *driver_handle;
    char aes_dev_name[20];

    if (!pstCtrl)
    {
        return -5;
    }

    driver_handle = (struct CRYPTO_DRIVER_HANDLE *) phCipher->opfd;

    phCipher->ps8AlgType = _FIND_MAP_STRING(alg_map,pstCtrl->enAlg);
    phCipher->ps8AlgMode = _FIND_MAP_STRING(work_mode_map,pstCtrl->enWorkMode);
    phCipher->u32KeyLen = _FIND_MAP_DATTA(key_len_map,pstCtrl->enKeyLen);
    phCipher->u32IVLen =  _FIND_MAP_DATTA(iv_key_len_map,pstCtrl->enIVLen);
    phCipher->ps8IVBuf = (char *)pstCtrl->u32IV;
    phCipher->ps8KeyBuf = (char *)pstCtrl->u32Key;
    phCipher->enKeySrc = pstCtrl->enKeySrc;

    if (phCipher->u32IVLen == 0)
    {
        phCipher->ps8IVBuf = NULL;
    }

    sprintf(aes_dev_name, "%s%s%s", phCipher->ps8AlgType, "-", phCipher->ps8AlgMode);
    driver_handle->crypto_obj = rt_algo_obj_find(RT_Algo_Class_Crypto, aes_dev_name);
    if (!driver_handle->crypto_obj)
    {
        printf("[crypt_api]: can't find the %s driver support..\n", aes_dev_name);
        return -4;
    }

    return 0;
}


int FH_CRYPTO_WriteOTPKey(unsigned int u32OptId, const unsigned char *pu8Key, unsigned int u32KeyLen)
{
    int ret = 0;

    if (u32OptId > 2)
    {
        printf("[crypt_api]: opt id is out of range, should be 0~2\n");
        return -2;
    }

    ret = crypto_efuse_write(u32OptId, pu8Key, u32KeyLen);
    if (ret < 0)
    {
        printf("[crypt_api]: efuse write failed\n");
        return ret;
    }

    return ret;
}

int FH_CRYPTO_WriteOTPDeviceID(const unsigned char *pu8Key, unsigned int u32KeyLen)
{
    int ret = 0;

    ret = crypto_efuse_write(EFUSE_ENTRY_RANGE, pu8Key, u32KeyLen);
    if (ret < 0)
    {
        printf("[crypt_api]: efuse write failed\n");
        return ret;
    }

    return 0;
}

int FH_CRYPTO_ReadOTPDeviceID(const unsigned char *pu8Key, unsigned int u32KeyLen)
{
    int ret = 0;

    ret = crypto_efuse_read(EFUSE_ENTRY_RANGE, pu8Key, u32KeyLen);
    if (ret < 0)
    {
        printf("[crypt_api]: efuse read failed\n");
        return ret;
    }

    return 0;
}

int FH_CRYPTO_Encrypt(CRYPTO_HANDLE *phCipher, unsigned int u32SrcPhyAddr,
        unsigned int u32DestPhyAddr, unsigned int u32ByteLength)
{
    struct CRYPTO_DRIVER_HANDLE *driver_handle;
    struct rt_crypto_request *request;
    int ret;

    phCipher->ps8AlgSrc = (char *)u32SrcPhyAddr;
    phCipher->ps8AlgDst = (char *)u32DestPhyAddr;
    phCipher->u32TextLen = u32ByteLength;
    request = &phCipher->request;
    PRINT_DBG("%s: type:%s ,mode:%s ,key len:%d ,iv_len:%d ,text len:%d ,key_src:%d\n",
            __func__,
            phCipher->ps8AlgType, phCipher->ps8AlgMode,
            phCipher->u32KeyLen, phCipher->u32IVLen,
            phCipher->u32TextLen,
            phCipher->enKeySrc);

    request->data_src = (unsigned char *)u32SrcPhyAddr;
    request->data_dst = (unsigned char *)u32DestPhyAddr;
    request->data_size = u32ByteLength;
    request->key = (unsigned char *)phCipher->ps8KeyBuf;
    request->key_size = phCipher->u32KeyLen;
    request->iv = (unsigned char *)phCipher->ps8IVBuf;
    request->iv_size = phCipher->u32IVLen;
    request->key_flag &= ~(AES_FLAG_SUPPORT_CPU_SET_KEY | AES_FLAG_SUPPORT_EFUSE_SET_KEY);
    if (phCipher->enKeySrc == CRYPTO_KEY_SRC_USER)
        request->key_flag |= AES_FLAG_SUPPORT_CPU_SET_KEY;
    else if (phCipher->enKeySrc == CRYPTO_KEY_SRC_EFUSE)
        request->key_flag |= AES_FLAG_SUPPORT_EFUSE_SET_KEY;
    else
        return -1;

    driver_handle = (struct CRYPTO_DRIVER_HANDLE *) phCipher->opfd;
    if (driver_handle->crypto_obj == NULL)
        return -4;
    ret = rt_algo_crypto_setkey(driver_handle->crypto_obj, request);
    if (0 != ret)
    {
        printf("[crypt_api]: crypt_cipher_crypt failed, ret=%d\n", ret);
        return ret;
    }

    ret = rt_algo_crypto_encrypt(driver_handle->crypto_obj, request);
    if (0 != ret)
    {
        printf("[crypt_api]: crypt_cipher_crypt failed, ret=%d\n", ret);
        return ret;
    }

    return 0;
}

int FH_CRYPTO_Decrypt(CRYPTO_HANDLE *phCipher, unsigned int u32SrcPhyAddr,
        unsigned int u32DestPhyAddr, unsigned int u32ByteLength)
{
    struct CRYPTO_DRIVER_HANDLE *driver_handle;
    struct rt_crypto_request *request;
    int ret;

    phCipher->ps8AlgSrc = (char *)u32SrcPhyAddr;
    phCipher->ps8AlgDst = (char *)u32DestPhyAddr;
    phCipher->u32TextLen = u32ByteLength;
    request = &phCipher->request;
    PRINT_DBG("%s, type:%s ,mode:%s ,key len:%d ,iv_len:%d ,text len:%d ,key_src:%d\n",
            __func__,
            phCipher->ps8AlgType, phCipher->ps8AlgMode,
            phCipher->u32KeyLen, phCipher->u32IVLen,
            phCipher->u32TextLen,
            phCipher->enKeySrc);

    request->data_src = (unsigned char *)u32SrcPhyAddr;
    request->data_dst = (unsigned char *)u32DestPhyAddr;
    request->data_size = u32ByteLength;
    request->key = (unsigned char *)phCipher->ps8KeyBuf;
    request->key_size = phCipher->u32KeyLen;
    request->iv = (unsigned char *)phCipher->ps8IVBuf;
    request->iv_size = phCipher->u32IVLen;
    request->key_flag &= ~(AES_FLAG_SUPPORT_CPU_SET_KEY | AES_FLAG_SUPPORT_EFUSE_SET_KEY);
    if (phCipher->enKeySrc == CRYPTO_KEY_SRC_USER)
        request->key_flag |= AES_FLAG_SUPPORT_CPU_SET_KEY;
    else if (phCipher->enKeySrc == CRYPTO_KEY_SRC_EFUSE)
        request->key_flag |= AES_FLAG_SUPPORT_EFUSE_SET_KEY;
    else
        return -1;

    driver_handle = (struct CRYPTO_DRIVER_HANDLE *) phCipher->opfd;
    if (driver_handle->crypto_obj == NULL)
        return -4;
    ret = rt_algo_crypto_setkey(driver_handle->crypto_obj, request);
    if (ret != 0)
    {
        printf("[crypt_api]: crypt_cipher_decrypt failed, ret=%d\n", ret);
        return ret;
    }
    ret = rt_algo_crypto_decrypt(driver_handle->crypto_obj, request);
    if (ret != 0)
    {
        printf("[crypt_api]: crypt_cipher_decrypt failed, ret=%d\n", ret);
        return ret;
    }

    return 0;
}

/********************
 *  add map switch. caution.
 *  app should know (8830 & 8630)  do not have this func but (8632 & 8833 & zy have)
 *  '*u32MapBuf' and 'u32MapBufSize' should like below
 *  u32MapBuf[0] = 0;
 *  u32MapBuf[1] = 8;
 *  u32MapBuf[2] = 4;
 *  u32MapBuf[3] = 12;
 *  u32MapBufSize = 4;
 *  para above means:
 *  [efuse_entry(0~3)]=>[aes_key(0)]
 *  [efuse_entry(8~11)]=>[aes_key(1)]
 *  [efuse_entry(4~7)]=>[aes_key(2)]
 *  [efuse_entry(12~15)]=>[aes_key(3)]
 *
 *******************/
int FH_CRYPTO_Mapswitch(CRYPTO_HANDLE *phCipher, unsigned int *u32MapBuf, unsigned int u32MapBufSize){
    int i;
    struct ex_key_map *p_map;
    struct rt_crypto_request *request;
    request = &phCipher->request;
    request->key_flag |= CRYPTO_EX_MEM_SWITCH_KEY | CRYPTO_EX_MEM_4_ENTRY_1_KEY;
    p_map = &request->adv.ex_key_para.map[0];
    request->adv.ex_key_para.map_size = u32MapBufSize;
    for(i = 0; i < u32MapBufSize; i++){
        p_map[i].crypto_key_no = i;
        p_map[i].ex_mem_entry = u32MapBuf[i];
    }
    return 0;
}


/**************api test : efuse dev id ***********/
#define ENTRY_LENGTH  16
#define OTP_3_LENGTH  8
int efuse_devid_write_read(void){
    int ret, i;
	CRYPTO_HANDLE pCryptoHandle;
    u8 result[OTP_3_LENGTH];
    u8 otp_device_id[OTP_3_LENGTH] =
    {
        0x11, 0x22, 0x33, 0x44, 0x55,
        0x66, 0x77, 0x88,
    };

	ret = FH_CRYPTO_Init();
	if(ret < 0)
	{
		printf("FH_CRYPTO_Init failed, ret = %d\n", ret);
	}
    FH_CRYPTO_CreateHandle(&pCryptoHandle);

    //write..
    ret = FH_CRYPTO_WriteOTPDeviceID(otp_device_id, OTP_3_LENGTH);
	if(ret < 0)
	{
		printf("FH_CRYPTO_WriteOTPKey failed, ret = %d\n", ret);
	}

    //read..
    ret = FH_CRYPTO_ReadOTPDeviceID(result, OTP_3_LENGTH);
    if(ret < 0)
    {
        printf("FH_CRYPTO_ReadOTPDeviceID failed, ret=%d\n", ret);
    }

    printf("device id: ");
    for(i = 0; i < OTP_3_LENGTH; i++)
        printf("0x%x, ", result[i]);
    printf("\n");

    ret = FH_CRYPTO_DestroyHandle(&pCryptoHandle);
	if(ret < 0)
	{
		printf("FH_CRYPTO_DestroyHandle failed, ret = %d\n", ret);
	}

	ret = FH_CRYPTO_DeInit();
	if(ret < 0)
	{
		printf("FH_CRYPTO_DeInit failed, ret = %d\n", ret);
	}
    return 0;
}


/****** efuse write key test ******/

//================ aes ecb 128=====================
static const unsigned char aes_ecb_128_key_buf[] = {
	0x2b,0x7e,0x15,0x16, 0x28,0xae,0xd2,0xa6, 0xab,0xf7,0x15,0x88, 0x09,0xcf,0x4f,0x3c,
};
//================ aes ecb 256=====================
static const unsigned char aes_ecb_256_key_buf[] = {
	0x60,0x3d,0xeb,0x10, 0x15,0xca,0x71,0xbe, 0x2b,0x73,0xae,0xf0, 0x85,0x7d,0x77,0x81,
	0x1f,0x35,0x2c,0x07, 0x3b,0x61,0x08,0xd7, 0x2d,0x98,0x10,0xa3, 0x09,0x14,0xdf,0xf4,
};



int efuse_key_write(void){
    int ret;
	CRYPTO_HANDLE pCryptoHandle;
	ret = FH_CRYPTO_Init();
	if(ret < 0)
	{
		printf("FH_CRYPTO_Init failed, ret = %d\n", ret);
	}
    FH_CRYPTO_CreateHandle(&pCryptoHandle);

	ret = FH_CRYPTO_WriteOTPKey(0, aes_ecb_128_key_buf, 16);
	if(ret < 0)
	{
		printf("FH_CRYPTO_WriteOTPKey failed, ret = %d\n", ret);
	}

	ret = FH_CRYPTO_WriteOTPKey(1, aes_ecb_256_key_buf, 32);
	if(ret < 0)
	{
		printf("FH_CRYPTO_WriteOTPKey failed, ret = %d\n", ret);
	}

    ret = FH_CRYPTO_DestroyHandle(&pCryptoHandle);
	if(ret < 0)
	{
		printf("FH_CRYPTO_DestroyHandle failed, ret = %d\n", ret);
	}

	ret = FH_CRYPTO_DeInit();
	if(ret < 0)
	{
		printf("FH_CRYPTO_DeInit failed, ret = %d\n", ret);
	}
    return 0;
}

/****** efuse lock test ******/

int efuse_lock(void){
    int ret;
	CRYPTO_HANDLE pCryptoHandle;
	ret = FH_CRYPTO_Init();
	if(ret < 0)
	{
		printf("FH_CRYPTO_Init failed, ret = %d\n", ret);
	}
    FH_CRYPTO_CreateHandle(&pCryptoHandle);

    //efuse的[0 ~ 15]entry lock, efuse的[32 ~ 47]entry lock, aes的[key0 ~ key7]lock
    FH_CRYPTO_SetLock(5);

    ret = FH_CRYPTO_DestroyHandle(&pCryptoHandle);
	if(ret < 0)
	{
		printf("FH_CRYPTO_DestroyHandle failed, ret = %d\n", ret);
	}

	ret = FH_CRYPTO_DeInit();
	if(ret < 0)
	{
		printf("FH_CRYPTO_DeInit failed, ret = %d\n", ret);
	}
    return 0;
}

/****** aes test with cpu or efuse ******/
static __attribute__((aligned(32)))   const unsigned char plain_text[] = {
	0x6b,0xc1,0xbe,0xe2, 0x2e,0x40,0x9f,0x96, 0xe9,0x3d,0x7e,0x11, 0x73,0x93,0x17,0x2a,
	0xae,0x2d,0x8a,0x57, 0x1e,0x03,0xac,0x9c, 0x9e,0xb7,0x6f,0xac, 0x45,0xaf,0x8e,0x51,
	0x30,0xc8,0x1c,0x46, 0xa3,0x5c,0xe4,0x11, 0xe5,0xfb,0xc1,0x19, 0x1a,0x0a,0x52,0xef,
	0xf6,0x9f,0x24,0x45, 0xdf,0x4f,0x9b,0x17, 0xad,0x2b,0x41,0x7b, 0xe6,0x6c,0x37,0x10,
};

static __attribute__((aligned(32))) const unsigned char aes_ecb_128_encrypt_text[] =
{
	0x3a,0xd7,0x7b,0xb4, 0x0d,0x7a,0x36,0x60, 0xa8,0x9e,0xca,0xf3, 0x24,0x66,0xef,0x97,
	0xf5,0xd3,0xd5,0x85, 0x03,0xb9,0x69,0x9d, 0xe7,0x85,0x89,0x5a, 0x96,0xfd,0xba,0xaf,
	0x43,0xb1,0xcd,0x7f, 0x59,0x8e,0xce,0x23, 0x88,0x1b,0x00,0xe3, 0xed,0x03,0x06,0x88,
	0x7b,0x0c,0x78,0x5e, 0x27,0xe8,0xad,0x3f, 0x82,0x23,0x20,0x71, 0x04,0x72,0x5d,0xd4,
};

static __attribute__((aligned(32))) const unsigned char aes_ecb_256_encrypt_text[] =
{
	0xf3,0xee,0xd1,0xbd, 0xb5,0xd2,0xa0,0x3c, 0x06,0x4b,0x5a,0x7e, 0x3d,0xb1,0x81,0xf8,
	0x59,0x1c,0xcb,0x10, 0xd4,0x10,0xed,0x26, 0xdc,0x5b,0xa7,0x4a, 0x31,0x36,0x28,0x70,
	0xb6,0xed,0x21,0xb9, 0x9c,0xa6,0xf4,0xf9, 0xf1,0x53,0xe7,0xb1, 0xbe,0xaf,0xed,0x1d,
	0x23,0x30,0x4b,0x7a, 0x39,0xf9,0xf3,0xff, 0x06,0x7d,0x8d,0x8f, 0x9e,0x24,0xec,0xc7,
};

// typedef struct FH_CRYPTO_CTRL_S
// {
//     unsigned int u32Key[8];
//     unsigned int u32IV[4];
//     CRYPTO_ALG_E enAlg;
//     CRYPTO_BIT_WIDTH_E  enBitWidth;
//     CRYPTO_WORK_MODE_E  enWorkMode;
//     CRYPTO_KEY_LENGTH_E enKeyLen;
//     CRYPTO_IV_LENGTH_E enIVLen;
//     CRYPTO_CTRL_CHANGE_FLAG_S enChangeFlag;
//     CRYPTO_KEY_SRC_E enKeySrc;
// } CRYPTO_CTRL_S;

int aes_crypto_with_cpu_or_efuse(void){
    unsigned char out_buf[256] = { 0 };
    unsigned int u32MapBuf[8];
    CRYPTO_CTRL_S hikCtrl;
    int ret;
	CRYPTO_HANDLE pCryptoHandle;
	ret = FH_CRYPTO_Init();
	if(ret < 0)
	{
		printf("FH_CRYPTO_Init failed, ret = %d\n", ret);
	}
    FH_CRYPTO_CreateHandle(&pCryptoHandle);

    /**
     *
     * aes cpu test
     *
     * **/
    printf("aes cpu test...\n");
    hikCtrl.enKeySrc = CRYPTO_KEY_SRC_USER;
	hikCtrl.enAlg = CRYPTO_ALG_AES;
	hikCtrl.enWorkMode = CRYPTO_WORK_MODE_ECB;
	hikCtrl.enIVLen = CRYPTO_IV_KEY_AES_0BIT;
	hikCtrl.enKeyLen = CRYPTO_KEY_AES_128BIT;
	memcpy(hikCtrl.u32Key, (char *) aes_ecb_128_key_buf,
	       sizeof(aes_ecb_128_key_buf));

	FH_CRYPTO_ConfigHandle(&pCryptoHandle, &hikCtrl);
    // encrypt
	FH_CRYPTO_Encrypt(&pCryptoHandle, (u32) plain_text,
			       (u32) &out_buf[0], sizeof(plain_text));

	if (0 != memcmp(&out_buf[0], aes_ecb_128_encrypt_text,
			sizeof(aes_ecb_128_encrypt_text)))
		printf("FAIL AES ECB 128 bit Encrypt test\n");
	else
		printf("PASS AES ECB 128 bit Encrypt test\n");
    // decrypt..
	FH_CRYPTO_Decrypt(&pCryptoHandle, (u32) aes_ecb_128_encrypt_text,
			       (u32)&out_buf[0], sizeof(aes_ecb_128_encrypt_text));

	if (0 != memcmp(&out_buf[0], plain_text, sizeof(plain_text)))
		printf("FAIL AES ECB 128 bit Decrypt test\n");
	else
		printf("PASS AES ECB 128 bit Decrypt test\n");


    /**
     *
     * aes efuse test with no map switch
     * if not set map switch ...efuse will map to aes with [0-3] to key[0]; [4-7] to key[1]..
     * **/
    printf("aes efuse test...\n");

    hikCtrl.enKeySrc = CRYPTO_KEY_SRC_EFUSE;
	hikCtrl.enAlg = CRYPTO_ALG_AES;
	hikCtrl.enWorkMode = CRYPTO_WORK_MODE_ECB;
	hikCtrl.enIVLen = CRYPTO_IV_KEY_AES_0BIT;
	hikCtrl.enKeyLen = CRYPTO_KEY_AES_128BIT;
	memcpy(hikCtrl.u32Key, (char *) aes_ecb_128_key_buf,
	       sizeof(aes_ecb_128_key_buf));

	FH_CRYPTO_ConfigHandle(&pCryptoHandle, &hikCtrl);
    // encrypt
	FH_CRYPTO_Encrypt(&pCryptoHandle, (u32) plain_text,
			       (u32) &out_buf[0], sizeof(plain_text));

	if (0 != memcmp(&out_buf[0], aes_ecb_128_encrypt_text,
			sizeof(aes_ecb_128_encrypt_text)))
		printf("FAIL AES ECB 128 bit Encrypt test\n");
	else
		printf("PASS AES ECB 128 bit Encrypt test\n");
    // decrypt..
	FH_CRYPTO_Decrypt(&pCryptoHandle, (u32) aes_ecb_128_encrypt_text,
			       (u32)&out_buf[0], sizeof(aes_ecb_128_encrypt_text));

	if (0 != memcmp(&out_buf[0], plain_text, sizeof(plain_text)))
		printf("FAIL AES ECB 128 bit Decrypt test\n");
	else
		printf("PASS AES ECB 128 bit Decrypt test\n");




    /**
     *
     * aes efuse test with map switch
     *
     * **/

    printf("aes 128 efuse map switch test...\n");
    hikCtrl.enKeySrc = CRYPTO_KEY_SRC_EFUSE;
	hikCtrl.enAlg = CRYPTO_ALG_AES;
	hikCtrl.enWorkMode = CRYPTO_WORK_MODE_ECB;
	hikCtrl.enIVLen = CRYPTO_IV_KEY_AES_0BIT;
	hikCtrl.enKeyLen = CRYPTO_KEY_AES_128BIT;
	memcpy(hikCtrl.u32Key, (char *) aes_ecb_128_key_buf,
	       sizeof(aes_ecb_128_key_buf));
    u32MapBuf[0] = 0;
    u32MapBuf[1] = 4;
    u32MapBuf[2] = 8;
    u32MapBuf[3] = 12;
    //map switch
    FH_CRYPTO_Mapswitch(&pCryptoHandle, u32MapBuf, 4);

	FH_CRYPTO_ConfigHandle(&pCryptoHandle, &hikCtrl);
    // encrypt
	FH_CRYPTO_Encrypt(&pCryptoHandle, (u32) plain_text,
			       (u32) &out_buf[0], sizeof(plain_text));

	if (0 != memcmp(&out_buf[0], aes_ecb_128_encrypt_text,
			sizeof(aes_ecb_128_encrypt_text)))
		printf("FAIL AES ECB 128 bit Encrypt test\n");
	else
		printf("PASS AES ECB 128 bit Encrypt test\n");
    // decrypt..
	FH_CRYPTO_Decrypt(&pCryptoHandle, (u32) aes_ecb_128_encrypt_text,
			       (u32)&out_buf[0], sizeof(aes_ecb_128_encrypt_text));

	if (0 != memcmp(&out_buf[0], plain_text, sizeof(plain_text)))
		printf("FAIL AES ECB 128 bit Decrypt test\n");
	else
		printf("PASS AES ECB 128 bit Decrypt test\n");




    printf("aes 256 efuse map switch test...\n");
    hikCtrl.enKeySrc = CRYPTO_KEY_SRC_EFUSE;
	hikCtrl.enAlg = CRYPTO_ALG_AES;
	hikCtrl.enWorkMode = CRYPTO_WORK_MODE_ECB;
	hikCtrl.enIVLen = CRYPTO_IV_KEY_AES_0BIT;
	hikCtrl.enKeyLen = CRYPTO_KEY_AES_256BIT;
	memcpy(hikCtrl.u32Key, (char *) aes_ecb_256_key_buf,
	       sizeof(aes_ecb_256_key_buf));

    u32MapBuf[0] = 16;
    u32MapBuf[1] = 20;
    u32MapBuf[2] = 24;
    u32MapBuf[3] = 28;
    u32MapBuf[4] = 32;
    u32MapBuf[5] = 36;
    u32MapBuf[6] = 40;
    u32MapBuf[7] = 44;

    //map switch
    FH_CRYPTO_Mapswitch(&pCryptoHandle, u32MapBuf, 8);

	FH_CRYPTO_ConfigHandle(&pCryptoHandle, &hikCtrl);
    // encrypt
	FH_CRYPTO_Encrypt(&pCryptoHandle, (u32) plain_text,
			       (u32) &out_buf[0], sizeof(plain_text));

	if (0 != memcmp(&out_buf[0], aes_ecb_256_encrypt_text,
			sizeof(aes_ecb_256_encrypt_text)))
		printf("FAIL AES ECB 256 bit Encrypt test\n");
	else
		printf("PASS AES ECB 256 bit Encrypt test\n");
    // decrypt..
	FH_CRYPTO_Decrypt(&pCryptoHandle, (u32) aes_ecb_256_encrypt_text,
			       (u32)&out_buf[0], sizeof(aes_ecb_256_encrypt_text));

	if (0 != memcmp(&out_buf[0], plain_text, sizeof(plain_text)))
		printf("FAIL AES ECB 256 bit Decrypt test\n");
	else
		printf("PASS AES ECB 256 bit Decrypt test\n");




    ret = FH_CRYPTO_DestroyHandle(&pCryptoHandle);
	if(ret < 0)
	{
		printf("FH_CRYPTO_DestroyHandle failed, ret = %d\n", ret);
	}

	ret = FH_CRYPTO_DeInit();
	if(ret < 0)
	{
		printf("FH_CRYPTO_DeInit failed, ret = %d\n", ret);
	}
    return 0;
}
